<script setup>
import { onMounted, onUnmounted } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/addons/renderers/CSS2DRenderer.js";

let scene, camera, renderer, labelRenderer;
let redSphere,
  blueCubes = [];
const attackLines = new Set();
const attackLabels = new Set();

// 初始化场景
function initScene(container) {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(
    75,
    container.clientWidth / container.clientHeight,
    0.1,
    1000
  );
  camera.position.set(0, 5, 15);
  camera.lookAt(0, 0, 0);

  // 初始化WebGL渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  renderer.setClearColor(0x000000, 1);
  renderer.setSize(container.clientWidth, container.clientHeight);
  container.appendChild(renderer.domElement);

  // 初始化CSS2D渲染器
  labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(container.clientWidth, container.clientHeight);
  labelRenderer.domElement.style.position = "absolute";
  labelRenderer.domElement.style.top = "0";
  container.appendChild(labelRenderer.domElement);
  // 确保WebGL渲染器在底层
  renderer.domElement.style.position = "relative";
  renderer.domElement.style.zIndex = "1";

  // 添加轨道控制器
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 0, 0); // 确保焦点在场景中心

  // 添加环境光
  const ambientLight = new THREE.AmbientLight(0x404040);
  scene.add(ambientLight);
  const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  directionalLight.position.set(5, 5, 5);
  scene.add(directionalLight);
}

function createRedSphere() {
  // 创建金字塔几何体
  const pyramidGeometry1 = new THREE.ConeGeometry(1, 2, 4);
  const pyramidGeometry2 = new THREE.ConeGeometry(1, 2, 4);

  // 旋转第二个金字塔使其倒置
  pyramidGeometry2.rotateY(Math.PI / 4); // 旋转45度使棱角对齐
  pyramidGeometry2.rotateX(Math.PI); // 翻转180度

  // 创建材质
  const material = new THREE.MeshPhongMaterial({
    color: 0xff0000,
    shininess: 100,
  });

  // 创建两个金字塔网格
  const pyramid1 = new THREE.Mesh(pyramidGeometry1, material);
  const pyramid2 = new THREE.Mesh(pyramidGeometry2, material);

  // 将第二个金字塔向上移动使其底部与第一个对齐
  pyramid2.position.y = -1; // 调整这个值使两个金字塔完美对接

  // 创建组并添加两个金字塔
  redSphere = new THREE.Group();
  redSphere.add(pyramid1);
  redSphere.add(pyramid2);

  scene.add(redSphere);
}

// 创建六个蓝色立方体
function createBlueCubes() {
  const radius = 8;
  for (let i = 0; i < 6; i++) {
    const angle = (i * Math.PI * 2) / 6;
    const geometry = new THREE.BoxGeometry(0.8, 0.8, 0.8);
    const material = new THREE.MeshPhongMaterial({ color: 0x0000ff });
    const cube = new THREE.Mesh(geometry, material);
    cube.position.x = radius * Math.cos(angle);
    cube.position.z = radius * Math.sin(angle);
    scene.add(cube);
    blueCubes.push(cube);
  }
}

// 创建弧形弹道（带尾迹箭头）
function createAttackCurve(start, end) {
  const geometry = new THREE.BufferGeometry();
  const count = 80; // 增加粒子数量
  const positions = new Float32Array(count * 3);
  const sizes = new Float32Array(count);
  const colors = new Float32Array(count * 3); // 添加颜色数组

  // 调整起点和终点位置，使线条从模型前方发射
  const direction = new THREE.Vector3().subVectors(end, start).normalize();
  const adjustedStart = start
    .clone()
    .add(direction.clone().multiplyScalar(0.8)); // 从模型前方发射
  const adjustedEnd = end.clone().add(direction.clone().multiplyScalar(-0.8)); // 进入模型内部

  // 控制点计算
  const controlPoint = new THREE.Vector3()
    .addVectors(adjustedStart, adjustedEnd)
    .multiplyScalar(0.5)
    .add(new THREE.Vector3(0, 5, 0));

  // 生成粒子数据
  for (let i = 0; i < count; i++) {
    const ratio = (count - i) / count;
    const t = ratio;
    const tt = t * t;
    const u = 1 - t;
    const uu = u * u;

    // 使用更高效的贝塞尔曲线计算
    const pos = new THREE.Vector3()
      .addScaledVector(start, uu)
      .addScaledVector(controlPoint, 2 * u * t)
      .addScaledVector(end, tt);

    // 增加随机偏移
    pos.addScaledVector(
      new THREE.Vector3(
        Math.random() - 0.5,
        Math.random() - 0.5,
        Math.random() - 0.5
      ),
      ratio * 0.5
    );

    positions[i * 3] = pos.x;
    positions[i * 3 + 1] = pos.y;
    positions[i * 3 + 2] = pos.z;

    // 优化尺寸变化 - 头部大尾部细（反转效果）
    sizes[i] = 0.8 * (1 - ratio) + 0.1 * Math.pow(ratio, 3); // 头部0.8，尾部0.1
    if (i < 5) sizes[i] = 0.8; // 增强头部粒子

    // 颜色渐变
    const baseColor =
      start === redSphere.position ? [1, 0.2, 0.2] : [0.2, 0.2, 1];
    const colorIntensity = Math.pow(1 - ratio, 3); // 更陡峭的衰减
    colors[i * 3] = baseColor[0] * colorIntensity;
    colors[i * 3 + 1] = baseColor[1] * colorIntensity;
    colors[i * 3 + 2] = baseColor[2] * colorIntensity;
  }

  geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute("size", new THREE.BufferAttribute(sizes, 1));
  geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3)); // 添加颜色属性

  const material = new THREE.PointsMaterial({
    size: 0.08,
    vertexColors: true, // 启用顶点颜色
    transparent: true,
    opacity: 0.98,
    blending: THREE.AdditiveBlending,
    sizeAttenuation: true,
    depthWrite: false,
  });

  const points = new THREE.Points(geometry, material);
  points.userData = {
    start: start.clone(),
    end: end.clone(),
    controlPoint: controlPoint, // 存储控制点
    progress: 0,
    speed: 0.008,
    positions: positions,
    sizes: sizes, // 存储尺寸数据
  };
  return points;
}

// 创建攻击文字标签
function createAttackText(text, position, isRed) {
  const div = document.createElement("div");
  div.textContent = text;
  div.style.color = "#fff";
  div.style.fontSize = "16px";
  div.style.padding = "2px 5px";
  div.style.borderRadius = "4px";
  div.style.backgroundColor = isRed
    ? "rgba(255, 0, 0, 0.5)"
    : "rgba(0, 0, 255, 0.5)"; // 添加半透明背景
  div.style.textShadow = "0 0 3px rgba(0,0,0,0.5)"; // 增强文字可读性

  const label = new CSS2DObject(div);
  label.position.copy(position);
  label.position.y += 0.5; // 增加Y轴偏移量，使文字在模型上方
  return label;
}

// 红色模型攻击
function redAttack() {
  // 随机选择3个立方体进行攻击
  const shuffledCubes = [...blueCubes]
    .sort(() => 0.5 - Math.random())
    .slice(0, 3);

  shuffledCubes.forEach((cube, index) => {
    // 随机攻击间隔 (1000-3000ms)
    const delay = 2000 + Math.random() * 2000;

    setTimeout(() => {
      const attackLine = createAttackCurve(redSphere.position, cube.position);
      attackLine.userData.isRedAttack = true;
      scene.add(attackLine);
      attackLines.add(attackLine);

      const label = createAttackText("攻击!", redSphere.position, true);
      scene.add(label);
      attackLabels.add(label);

      attackLine.userData.onComplete = () => {
        scene.remove(label);
        attackLabels.delete(label);
        blueCounterAttack(cube);
      };
    }, index * delay); // 使用随机延迟
  });
}

// 蓝色模型反击
function blueCounterAttack(cube) {
  // 添加随机延迟 (300-1000ms)
  const delay = 300 + Math.random() * 200;
  setTimeout(() => {
    const attackLine = createAttackCurve(cube.position, redSphere.position); // 终点设为红球当前位置
    scene.add(attackLine);
    attackLines.add(attackLine);

    const label = createAttackText(
      "反击!",
      cube.position.clone().add(new THREE.Vector3(0, 0.5, 0), false)
    ); // 添加Y轴偏移
    scene.add(label);
    attackLabels.add(label);

    // 新增完成回调
    attackLine.userData.onComplete = () => {
      scene.remove(label);
      attackLabels.delete(label);
    };

    attackLine.userData.endTarget = redSphere;
    attackLine.userData.cube = cube; // 保存攻击源立方体
  }, delay);
}

// 添加命中特效
function createHitEffect(position) {
  const particles = new THREE.BufferGeometry();
  const count = 50;
  const posArray = new Float32Array(count * 3);

  for (let i = 0; i < count * 3; i += 3) {
    posArray[i] = position.x + (Math.random() - 0.5);
    posArray[i + 1] = position.y + (Math.random() - 0.5);
    posArray[i + 2] = position.z + (Math.random() - 0.5);
  }

  particles.setAttribute("position", new THREE.BufferAttribute(posArray, 3));
  const material = new THREE.PointsMaterial({
    size: 0.1,
    color: 0x00ffff,
    transparent: true,
    opacity: 0.7,
    blending: THREE.AdditiveBlending,
  });

  const effect = new THREE.Points(particles, material);
  scene.add(effect);
  setTimeout(() => scene.remove(effect), 300);
}

function animate() {
  requestAnimationFrame(animate);
  attackLines.forEach((line) => {
    if (line.userData) {
      // 更新目标位置
      if (line.userData.endTarget) {
        line.userData.end = line.userData.endTarget.position.clone();
      }
      // 优化进度更新逻辑
      if (line.userData.progress < 1.0) {
        line.userData.progress += line.userData.speed;
      }
      // 渐隐系数计算
      const fadeOut = Math.max(0, 1 - (line.userData.progress - 1) * 3); // 加快渐隐速度
      // 动态尺寸效果
      const sizes = line.userData.sizes;
      const now = performance.now(); // 使用performance.now()替代Date.now()
      for (let i = 0; i < sizes.length; i++) {
        if (i > sizes.length - 5) {
          sizes[i] = 0.4 + Math.sin(now * 0.01) * 0.1;
        }
        if (i < sizes.length - 1) {
          sizes[i] = sizes[i] * 0.9 + sizes[i + 1] * 0.05;
        }
      }
      line.geometry.attributes.size.needsUpdate = true;

      // 轨迹计算
      const currentProgress = line.userData.progress;
      const positions = line.userData.positions;
      const totalParticles = positions.length / 3;

      const trailLength = 0.5; // 使用固定值避免随机波动导致的异常
      // 确保headPosition不会小于0
      const headPosition = Math.min(currentProgress, 1);
      // tailStart应该始终小于headPosition
      const tailStart = Math.max(headPosition - trailLength, 0);
      // 穿透效果处理
      let finalEnd = line.userData.end.clone();
      if (currentProgress >= 1) {
        const overflow = currentProgress - 1;
        const direction = new THREE.Vector3()
          .subVectors(line.userData.end, line.userData.start)
          .normalize();
        finalEnd.add(direction.multiplyScalar(overflow * 2));
      }

      // 更新粒子位置
      for (let i = 0; i < totalParticles; i++) {
        const particleT = tailStart + (i / totalParticles) * trailLength;
        const clampedT = Math.min(Math.max(particleT, tailStart), headPosition);
        const pos = new THREE.Vector3()
          .addScaledVector(line.userData.start, Math.pow(1 - clampedT, 2))
          .addScaledVector(
            line.userData.controlPoint,
            2 * (1 - clampedT) * clampedT
          )
          .addScaledVector(finalEnd, Math.pow(clampedT, 2));

        pos.y += Math.sin(clampedT * Math.PI * 2) * 0.3;

        positions[i * 3] = pos.x;
        positions[i * 3 + 1] = pos.y;
        positions[i * 3 + 2] = pos.z;

        // 动态颜色和尺寸（增加渐隐效果）
        const fade = 1 - (clampedT - tailStart) / trailLength;
        const sizeScale = 1 + Math.sin(clampedT * Math.PI * 2) * 0.2;
        line.geometry.attributes.size.array[i] =
          sizes[i] * fade * sizeScale * fadeOut;
      }

      line.geometry.attributes.position.needsUpdate = true;

      // 碰撞检测与移除（增加渐隐条件）
      if (line.userData.progress >= 1.0 || fadeOut <= 0) {
        scene.remove(line);
        attackLines.delete(line);
        if (line.userData.onComplete) line.userData.onComplete();
        if (line.userData.endTarget) {
          // 在目标模型内部创建命中效果
          const hitPosition = line.userData.endTarget.position.clone();
          createHitEffect(hitPosition);
        }
      }
    }
  });

  // 模型旋转动画
  redSphere.rotation.y += 0.01;
  blueCubes.forEach((cube) => (cube.rotation.y += 0.02));

  // 统一渲染
  renderer.render(scene, camera);
  labelRenderer.render(scene, camera);
}

// 组件挂载时初始化
onMounted(() => {
  const container = document.getElementById("battle-container");
  initScene(container);
  createRedSphere();
  createBlueCubes();
  animate();
  // 改为随机间隔的攻击循环 (3000-6000ms)
  setInterval(redAttack, 3000 + Math.random() * 3000);
});

// 组件卸载时清理
onUnmounted(() => {
  attackLines.forEach((line) => scene.remove(line));
  attackLabels.forEach((label) => scene.remove(label));
  renderer.dispose();
  labelRenderer.dispose();
});
</script>

<template>
  <div id="battle-container" class="w-full h-screen"></div>
</template>


 <style>
#battle-container {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}
.w-full {
  height: 100%;
  width: 100%;
}
</style>